While the perspective version looks great, there remains one problem. Move the time around until the rotating grey sphere ducks underneath the ground.
Hmm. Even though we've made it look like a mathematically perfect sphere, it does not
act like one to the depth buffer. As far as it is concerned, it's just a circle
(remember: discard
prevents depth writes and tests as well).
Is that the end for our impostors? Hardly.
Part of the fragment shader's output is a depth value. If you do not write one, then
OpenGL will happily use gl_FragCoord.z
as the depth output from the
fragment shader. This value will be depth tested against the current depth value and, if
the test passes, written to the depth buffer.
But we do have the ability to write a depth value ourselves. To see how this is done, load up the tutorial (using the same code again) and press the H key. This will cause all impostors to use depth-correct shaders.
This shader is identical to the ray traced version, except for these lines in the fragment shader:
Example 13.4. Depth Correct Fragment Shader
Impostor(cameraPos, cameraNormal); //Set the depth based on the new cameraPos. vec4 clipPos = cameraToClipMatrix * vec4(cameraPos, 1.0); float ndcDepth = clipPos.z / clipPos.w; gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;
Basically, we go through the process OpenGL normally goes through to compute the
depth. We just do it on the camera-space position we computed with the ray tracing
function. The position is transformed to clip space. The perspective division happens,
transforming to normalized device coordinate (NDC) space. The depth
range function is applied, forcing the [-1, 1] range in the fragment shader to the range
that the user provided with glDepthRange.
We write the final depth to a built-in output variable
gl_FragDepth.